package motodev.app;

import java.util.Timer;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.Ticker;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class Connect4 extends MIDlet implements CommandListener {

	private MyGameCanvas game;
	private List startOptions;
	private static Display myDisplay;
	public static boolean gameOver = true;
	private Timer timer = new Timer();
	
	public static boolean isBroadcastingY = false;
	public static boolean iHaveKey = false;
	public static boolean opponentHasKey = false;
	public static boolean isFirstPlayer;
	
	// Cryptographic information
	public int[] pg;
	public int x;
	public int myY;
	public Integer otherY;
	public static int key;
	
	

	/**
	 * Takes input from the game canvas and determines if there is a winner.
	 * @param board Game board to be tested
	 * @param row Row that corresponds to the last checker placed.
	 * @param col Column that corresponds to the last checker placed.
	 * @return true if a winner false otherwise.
	 */
	public Connect4() {
		myDisplay = Display.getDisplay(this);
		
		Ticker ticker = new Ticker("Connect 3 - The classic game, now on your mobile device!");
		startOptions = new List("How do you want to find a game?", List.IMPLICIT);
		startOptions.append("Create a game", null);
		startOptions.append("Find an existing game", null);
		startOptions.addCommand(new Command("Start game", Command.ITEM, 1));
		startOptions.addCommand(new Command("Find game", Command.ITEM, 1));
		startOptions.addCommand(new Command("Quit", Command.CANCEL, 1));
		startOptions.setCommandListener(this);
		startOptions.setTicker(ticker);

	}

	/**
	 * Destroys running application
	 */
	protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
		gameOver = true;
	}

	/**
	 * Pause application kills the running application 
	 */
	protected void pauseApp() {
		gameOver = true;
		game = null;
	}

	/**
	 * Sets up the display to show the title screen
	 */
	protected void startApp() {
		myDisplay.setCurrent(startOptions);
		start_run();
	}

	/**
	 * Checks is the command that is given and responds accordingly.
	 * Quits game is cancel is pressed and plays again is the asscoiated
	 * button is pressed.
	 */
	public void commandAction(Command c, Displayable d) {
		
		// Start options
		if (d.equals(startOptions)) {
			
			if (c.getCommandType() == Command.CANCEL) {
				this.notifyDestroyed();
			} else {
				int index = startOptions.getSelectedIndex();
				switch (index) {
				case 0:
					if (!isBroadcastingY)
					initiateKeyExchange();
					// TODO for demo only
					game = new MyGameCanvas(this);
					//change display to gameFrame
					myDisplay.setCurrent(game);	
					//start game
					gameOver = false;
					game.start();
					break;
				
				case 1:
					if (!isBroadcastingY)
					joinKeyExchange();
					break;
				}
			}
		}
		
		// Commands from game canvas
		else if (d.equals(game)) {
			switch (c.getCommandType()) {
			case Command.OK:
				game = new MyGameCanvas(this);
				//change display to gameFrame
				myDisplay.setCurrent(game);	
				//start game
				gameOver = false;
				game.start();
				break;
			
			case Command.CANCEL:
				this.notifyDestroyed();
				break;
			}
		}
	}

	/**
	 * Called when the game is over. Adds play again and quit to the main
	 * screen and a command listener to quit application.
	 */
	public void gameOver() {
		game.addCommand(new Command("Play again", Command.OK, 1));
		game.addCommand(new Command("Quit", Command.CANCEL, 1));
		game.setCommandListener(this);
		
	}
	
	// RMS communication methods

	/**
	 * Begins the execution of mote communication logic
	 */
	private void start_run() {
		RMS.reset_record();
		Clock mClock = new Clock(this);
		timer.schedule(mClock,0,500);
		//set channel
		RMS.set_app_channel((byte)1);
		
		
	}

	/**
	 * Called to reset all mote communication data
	 */
	private void end_run() {
		RMS.reset_record();  		
	}
	
	/**
	 * Called when the device has received a message; Key exchange information
	 * and encrypted game player moves are receieved here.
	 * @param cmd
	 */
	public void received_cmd(byte[] cmd) {
		
//		System.out.println("RECEIVED: " + cmd);
//		//receive a message from another phone
//  		if(cmd==null)
//  			return;
//  		
//  		// TODO Decrypt received message
//  			
//  		// Determine what to do based on message identifier prefix
//  		switch(cmd[0]) {
//  		
//  		// Execute the opponent's move
//  		case 'm':
			if (game != null) {
				if (!game.myTurn && !game.gameFinished) {
		  			// TODO 
					game.moveCursorRightToNextEmptySpace();
					int opponentCursorPos = game.cursorPos;//Cryptography.Decrypt(cmd, String.valueOf(key).getBytes());//game.cursorPos;
		  			game.opponentMove(opponentCursorPos);
//				}
//			}
//			break;
//		
//		// Receive the opponents 'Y' in key exchange
//  		case 'y':
//  			String response = String.valueOf(cmd);
//  			otherY = Integer.valueOf(response.substring(1));
//  			
//  			// Calculate secret key
//  			key = Cryptography.GenerateSecretKey(otherY.intValue(), x, pg[0]);
//  			iHaveKey = true;
//  			
//  			break;
//  			
//  		// This is received when your 'Y' has been received by the opponent
//  		case 'a':
//  			if (cmd[1] == 'c' && cmd[2] == 'k') {
//  				opponentHasKey = true;
//  				// No need to rebroadcast y
//  				isBroadcastingY = false;
//  				
//  				// Begin game		
//  				game = new MyGameCanvas(this);
//				//change display to gameFrame
//				myDisplay.setCurrent(game);
//				//start game
//				gameOver = false;
//				game.start();
  			}
  		}
  		
	}
	
	/**
	 * Called when a player creates a new game in order to set up a game session with
	 * an opponent
	 */
	private void initiateKeyExchange() {
		
		// The initiator will be the first player
		isFirstPlayer = true;
		
		// Get prime number p and generator g
		pg = Cryptography.BeginKeyExchange();
		
		// Pick a secret number x
		x = Cryptography.PickNumber();
		
		// Generate and send y
		myY = Cryptography.GenerateY(pg[0], pg[1], x);
		
		System.out.println("P: " + pg[0] + "   G: " + pg[1]);
		System.out.println("X: " + x + "   Y: " + myY);
		//System.out.println("Key: " + Cryptography.GenerateSecretKey(otherY.intValue(), x, pg[0]));
		
		isBroadcastingY = true;
		
		
	}
	
	/**
	 * Called when a user wants to join an existing session
	 */
	private void joinKeyExchange() {	
		// The joiner of the game will be the second player
		isFirstPlayer = false;
		
		// Get prime number p and generator g
		pg = Cryptography.BeginKeyExchange();
		
		// Pick a secret number x
		x = Cryptography.PickNumber();
		
		// Generate and send y
		myY = Cryptography.GenerateY(pg[0], pg[1], x);
		isBroadcastingY = true;
		
	}
	
	/**
	 * Broadcasts the player's 'Y' component of the secret key
	 */
	public void broadcastY() {
		String yPrefix = "y";
		String stringY = String.valueOf(myY);
		String broadcastY = yPrefix.concat(stringY);
		RMS.send_cmd(broadcastY.getBytes());
		System.out.print(broadcastY + "  ");
	}
}



























